package org.tulkas.robot.http.headers;

import java.util.Date;

import org.apache.http.Header;
import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.HeaderGroup;
import org.tulkas.robot.exception.SystemException;

/**
 * Base class for RequestHeaders and ResponseHeaders, including general http headers and entity headers.
 * Default values for every header element is null, if null is set the element not include in the http message.
 * For header reference, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">W3 Http protocol section 14</a>
 * @author <a href="mailto:tulkas.web@gmail.com">Tulkas</a>
 *
 */
public abstract class HttpHeaders {
	private HeaderGroup headerGroup = new HeaderGroup();

	protected Date parseDate(String dateStr) {
		if (dateStr != null) {
			try {
				return DateUtils.parseDate(dateStr);
			} catch (DateParseException e) {
				throw new SystemException("Can not parse date from Header", e);
			}
		} else
			return null;
	}

	/**
	 * Cache-Control header, e.g. "max-age=10"
	 */
	public String getCacheControl() {
		return getHeader("Cache-Control");
	}

	public void setCacheControl(String cacheControl) {
		updateHeader("Cache-Control", cacheControl);
	}

	/**
	 * Connection header, e.g. "close"
	 */
	public String getConnection() {
		return getHeader("Connection");
	}

	public void setConnection(String connection) {
		updateHeader("Connection", connection);
	}

	/**
	 * Date header, will be format to http date, e.g. "Tue, 11 Jul 2000 18:23:51 GMT"
	 */
	public Date getDate() {
		String str = getHeader("Date");
		return parseDate(str);
	}

	public void setDate(Date date) {
		updateHeader("Date", DateUtils.formatDate(date));
	}

	/**
	 * Pragma header, e.g. "no-cache"
	 */
	public String getPragma() {
		return getHeader("Pragma");
	}

	public void setPragma(String pragma) {
		updateHeader("Pragma", pragma);
	}

	/**
	 * Trailer header, e.g. "Date"
	 */
	public String getTrailer() {
		return getHeader("Trailer");
	}

	public void setTrailer(String trailer) {
		updateHeader("Trailer", trailer);
	}

	/**
	 * TransferEncoding header, e.g. "chunked"
	 */
	public String getTransferEncoding() {
		return getHeader("Transfer-Encoding");
	}

	public void setTransferEncoding(String transferEncoding) {
		updateHeader("Transfer-Encoding", transferEncoding);
	}

	/**
	 * Upgrade header, e.g. "SHTTP/1.3"
	 */
	public String getUpgrade() {
		return getHeader("Upgrade");
	}

	public void setUpgrade(String upgrade) {
		updateHeader("Upgrade", upgrade);
	}

	/**
	 * Via header, e.g. "HTTP/1.1 Proxy1, HTTP/1.1 Proxy2"
	 */
	public String getVia() {
		return getHeader("Via");
	}

	public void setVia(String via) {
		updateHeader("Via", via);
	}

	/**
	 * Warning header, e.g. "112 Disconnected Operation"
	 */
	public String getWarning() {
		return getHeader("Warning");
	}

	public void setWarning(String warning) {
		updateHeader("Warning", warning);
	}

	/**
	 * Allow header, e.g. "GET, HEAD"
	 */
	public String getAllow() {
		return getHeader("Allow");
	}

	public void setAllow(String allow) {
		updateHeader("Allow", allow);
	}

	/**
	 * Content-Encoding header, e.g. "gzip"
	 */
	public String getContentEncoding() {
		return getHeader("Content-Encoding");
	}

	public void setContentEncoding(String contentEncoding) {
		updateHeader("Content-Encoding", contentEncoding);
	}

	/**
	 * Content-Language header, e.g. "en"
	 */
	public String getContentLanguage() {
		return getHeader("Content-Language");
	}

	public void setContentLanguage(String contentLanguage) {
		updateHeader("Content-Language", contentLanguage);
	}

	/**
	 * Content-Length header, e.g. "8445"
	 */
	public Long getContentLength() {
		String str = getHeader("Content-Length");
		if (str != null)
			return Long.parseLong(str);
		else
			return null;
	}

	public void setContentLength(Long contentLength) {
		updateHeader("Content-Length", contentLength.toString());
	}

	/**
	 * Content-Location header, e.g. "http://localhost/page.html"
	 */
	public String getContentLocation() {
		return getHeader("Content-Location");
	}

	public void setContentLocation(String contentLocation) {
		updateHeader("Content-Location", contentLocation);
	}

	/**
	 * Content-MD5 header
	 */
	public String getContentMD5() {
		return getHeader("Content-MD5");
	}

	public void setContentMD5(String contentMD5) {
		updateHeader("Content-MD5", contentMD5);
	}

	/**
	 * Content-Range header, e.g. "bytes 2543-4532/7898"
	 */
	public String getContentRange() {
		return getHeader("Content-Range");
	}

	public void setContentRange(String contentRange) {
		updateHeader("Content-Range", contentRange);
	}

	/**
	 * Content-Type header, e.g. "text/html"
	 */
	public String getContentType() {
		return getHeader("Content-Type");
	}

	public void setContentType(String contentType) {
		updateHeader("Content-Type", contentType);
	}

	/**
	 * Expires header, will be format to http date, e.g. "Tue, 11 Jul 2000 18:23:51 GMT"
	 */
	public Date getExpires() {
		String str = getHeader("Expires");
		return parseDate(str);
	}

	public void setExpires(Date expires) {
		updateHeader("Expires", DateUtils.formatDate(expires));
	}

	/**
	 * Last-Modified header, will be format to http date, e.g. "Tue, 11 Jul 2000 18:23:51 GMT"
	 */
	public Date getLastModified() {
		String str = getHeader("Last-Modified");
		return parseDate(str);
	}

	public void setLastModified(Date lastModified) {
		updateHeader("Last-Modified", DateUtils.formatDate(lastModified));
	}

	public void addHeader(String key, String value) {
		headerGroup.addHeader(new BasicHeader(key, value));
	}

	public void updateHeader(String key, String value) {
		headerGroup.updateHeader(new BasicHeader(key, value));
	}

	public String getHeader(String key) {
		Header hd = headerGroup.getFirstHeader(key);
		if (hd == null)
			return null;
		else
			return headerGroup.getFirstHeader(key).getValue();
	}

	public Header[] getHeaders(String key) {
		return headerGroup.getHeaders(key);
	}

	public Header[] getAllHeaders() {
		return headerGroup.getAllHeaders();
	}

	public void setHeaders(Header[] headers) {
		headerGroup.setHeaders(headers);
	}

	public void clear() {
		headerGroup.clear();
	}

	@Override
	public String toString() {
		return headerGroup.toString();
	}
}
